package com.flexfiltering.view.controls
{

import com.flexfiltering.view.collections.FilteredCollectionView;
import com.flexfiltering.view.controls.completionInputClasses.CompletionInputMenu;
import com.flexfiltering.view.util.CollectionUtil;

import flash.events.Event;
import flash.events.FocusEvent;
import flash.events.KeyboardEvent;
import flash.geom.Point;
import flash.ui.Keyboard;

import mx.collections.ArrayCollection;
import mx.controls.List;
import mx.controls.TextInput;
import mx.events.CollectionEvent;
import mx.events.CollectionEventKind;
import mx.events.ListEvent;
import mx.events.MenuEvent;
import mx.managers.IFocusManagerComponent;
import mx.managers.PopUpManager;
import mx.styles.ISimpleStyleClient;

[Event(type="events.TokenFieldEvent",name="requestCompletions")]	
	
public class CompletionInput extends TextInput
{

	// @------------------------------------------------------ STATIC PROPERTIES
	// @-------------------------------------------------------PUBLIC PROPERTIES
	
	//----------------------------------
	//  completions
	//----------------------------------
	
	protected var completionsCollection:ArrayCollection;
	
	protected var completionsChanged:Boolean;
	
	[Bindable()]
	/**
	 *  
	 * 
	 * 	@default 
	 */ 
	public function get completions() : Object
	{
	    return completionsCollection;
	}
	
	/**
	 *  @private
	 */
	public function set completions ( val:Object ) : void
	{
		if ( completionsCollection )
			completionsCollection.removeEventListener( CollectionEvent.COLLECTION_CHANGE, 
													   completionsChangeHandler );
		
		completionsCollection = CollectionUtil.objectToCollection(val) as ArrayCollection;
		
		completionsCollection.addEventListener( CollectionEvent.COLLECTION_CHANGE, 
									 			completionsChangeHandler,
									 			false, 0, true );
		
		var event:CollectionEvent = new CollectionEvent(CollectionEvent.COLLECTION_CHANGE);
        	event.kind = CollectionEventKind.RESET;
        
        completionsChangeHandler(event);
        dispatchEvent(event);
	}
	
	//----------------------------------
	//  labelField
	//----------------------------------

	private var _labelField:String = "label";

	[Bindable()]
	/**
	 *  
	 * 
	 * 	@default 
	 */ 
	public function get labelField() : String
	{
	    return _labelField;
	}

	/**
	 *  @private
	 */
	public function set labelField ( val:String ) : void
	{
		if ( _labelField != val )
		{
			_labelField = val;
			
			if ( menu )
				menu.labelField = val
		}
	}
	
	//----------------------------------
	//  labelFunction
	//----------------------------------

	private var _labelFunction:Function;

	[Bindable()]
	/**
	 *  
	 * 
	 * 	@default 
	 */ 
	public function get labelFunction() : Function
	{
	    return _labelFunction;
	}

	/**
	 *  @private
	 */
	public function set labelFunction ( val:Function ) : void
	{
		if ( _labelFunction != val )
		{
			_labelFunction = val;
			
			if ( menu )
				menu.labelFunction = val
		}
	}
	
	// @---------------------------------------------------- INTERNAL PROPERTIES
	
	protected var menu:List;
	
	// @-------------------------------------------------- OVERRIDDEN PROPERTIES
	// @------------------------------------------------------------ CONSTRUCTOR
	
	public function CompletionInput ()
	{
		super();
		
		addEventListener(Event.CHANGE, changeHandler);
	}
	
	// @--------------------------------------------------------- PUBLIC METHODS
	// @------------------------------------------------------- INTERNAL METHODS
	
	//----------------------------------
	//  getMenu
	//----------------------------------
	
	protected function getMenu () : List
	{
		if ( !menu )
		{
			menu = new CompletionInputMenu();
			menu.visible = false;
			menu.owner = this;
			menu.labelField = _labelField
			menu.labelFunction = _labelFunction;
			
			if (menu is IFocusManagerComponent)
	            IFocusManagerComponent(menu).focusEnabled = false;
	        
	        if (menu is ISimpleStyleClient)
	            ISimpleStyleClient(menu).styleName = 
	            	getStyle("menuStyleName");
			
			menu.addEventListener( MenuEvent.ITEM_CLICK,
								   menu_itemClickHandler );
								   
			PopUpManager.addPopUp(menu, this, false);
		}
		
		return menu;
	}
	
	//----------------------------------
	//  displayMenu
	//----------------------------------
	
	protected function displayMenu (show:Boolean) : void
	{
		if (!initialized)
           return;
        
        var popUp:List = getMenu();
        
		if ( show )
		{
			if ( show != popUp.visible )
			{
				PopUpManager.bringToFront(popUp);
			}
			
			popUp.validateNow();
			var point:Point = new Point(0, unscaledHeight);
		    
		    point = localToGlobal(point);
		    point = popUp.parent.globalToLocal(point);
		    
		   	var padding:Number = 20;
		    
		    var hSpace:Number = screen.width - (padding * 2);
		    
		    if ( popUp.percentWidth )
		    {
		    	popUp.width = hSpace * (popUp.percentWidth/100);
		    }
		    
			popUp.width = Math.max(Math.min(hSpace,popUp.width),unscaledWidth);
			
			var hSpaceRight:Number = screen.width - padding - point.x
			
			var xoff:Number = Math.min(hSpaceRight - popUp.width,0);
			
			var xpos:Number = point.x + xoff;
			
			var vSpaceBelow:Number = screen.height - padding - point.y;
			var vSpaceAbove:Number = point.y - padding - unscaledHeight;
			var ypos:Number = point.y;
			
			// there's not room for it below without resizing
			if ( vSpaceBelow < popUp.height )
			{
				// check if there's room for it above
				if ( vSpaceAbove < popUp.height )
				{
					// if we're in here, resizing is inevitable, so check to see
					// if we have more room above or below
					if ( vSpaceAbove > vSpaceBelow )
					{
						popUp.height = vSpaceAbove;
						ypos = point.y - unscaledHeight - vSpaceAbove;
					}
					else
					{
						popUp.height = vSpaceBelow;
					}
				}
				else
				{
					ypos = point.y - unscaledHeight - popUp.height;
				}
			}
			
			popUp.move(xpos,ypos);
		}
	 	
	 	popUp.visible = show;
	}
	
	//----------------------------------
	//  acceptSuggestion
	//----------------------------------
	
	protected function acceptSuggestion () : void
	{
		text = getMenu().itemToLabel(menu.selectedItem);
		displayMenu(false);
		callLater(selectAll);
	}
	
	//----------------------------------
	//  values
	//----------------------------------
	
	protected function selectAll () : void
	{
		selectionBeginIndex = 0;
		selectionEndIndex = text.length;
	}
	
	// @----------------------------------------------------- OVERRIDDEN METHODS
	
	override protected function createChildren():void
	{
		super.createChildren();
	}
	
	//----------------------------------
	//  commitProperties
	//----------------------------------
	
	override protected function commitProperties():void
	{
		super.commitProperties();
		
		if ( completionsChanged )
		{
			if ( completions.length > 0 )
			{
				getMenu().dataProvider = completions;
				displayMenu(true);
			}
			else
			{
				displayMenu(false);
			}
			
			completionsChanged = false;
		}
	}
	// @--------------------------------------------------------- EVENT HANDLERS
	
	//----------------------------------
	//  changeHandler
    //----------------------------------
	
	protected function changeHandler ( event:Event ) : void
	{
		if ( !text || text == "")
		{
			displayMenu(false);
			return;	
		}
		if ( completions is FilteredCollectionView )
		{
			(completions as FilteredCollectionView).filterSubstring = text;
		}
	}
	
	//----------------------------------
	//  collectionChangeHandler
    //----------------------------------
	
	protected function completionsChangeHandler ( event:Event ) : void
	{
		completionsChanged = true;
		invalidateProperties();
	}
	
	//----------------------------------
	//  menu_itemClickHandler
    //----------------------------------
	
	protected function menu_itemClickHandler ( event:ListEvent=null ) : void
	{
		acceptSuggestion();
	}
	
	// @---------------------------------------------- OVERRIDDEN EVENT HANDLERS
	
	//----------------------------------
	//  keyDownHandler
	//----------------------------------
	
	override protected function keyDownHandler ( event:KeyboardEvent ) : void
	{
		super.keyDownHandler(event);
		
		if ( getMenu().visible &&
             ( event.keyCode == Keyboard.UP ||
               event.keyCode == Keyboard.DOWN ) )
        {
            // Redispatch the event to the menu or browser
            // and let its keyDownHandler() handle it.
            event.preventDefault();
            event.stopPropagation();
            event.stopImmediatePropagation();
            getMenu().dispatchEvent(event);
            
            // HACK: by default, pressing the up key will move the text field 
       		// cursor fo the beginning of the field. This code keeps it in place
       		
            selectionBeginIndex = textField.caretIndex;
            selectionEndIndex = textField.caretIndex;
        }
        
        if ( getMenu().visible && event.keyCode == Keyboard.ENTER )
        {
            // Redispatch the event to the menu or browser
            // and let its keyDownHandler() handle it.
            event.preventDefault();
            event.stopPropagation();
            acceptSuggestion();
        }
        
        if ( getMenu().visible && event.keyCode == Keyboard.ESCAPE )
        {
            // Redispatch the event to the menu or browser
            // and let its keyDownHandler() handle it.
            event.preventDefault();
            event.stopPropagation();
           	displayMenu(false);
        }
	}
	
	//----------------------------------
	//  focusInHandler
	//----------------------------------
	
	override protected function focusInHandler(event:FocusEvent):void
	{
		super.focusInHandler(event);
		callLater(selectAll);
	}
	
	//----------------------------------
	//  focusOutHandler
	//----------------------------------
	
	override protected function focusOutHandler(event:FocusEvent):void
	{
		super.focusOutHandler(event);
		if ( menu.visible )
		{
			acceptSuggestion();
		}
	}

} // class
} // package